//
//  Timber.swift
//
//  Created by 于虎拴 on 2022/8/25.
//

import Foundation
import os

private func getSimpleName(_ file: String) -> String {
  return (file as NSString).lastPathComponent
}

private func getThreadId() -> Int32 {
  // Thread.current: <_NSMainThread: 0x60000267c440>{number = 1, name = main}
  let input = "\(Thread.current)"
  var id: Int32 = 0
  if #available(iOS 16.0, *) {
    let regex = /number = (\d+),/
    if let match = try? regex.firstMatch(in: input) {
      id = Int32(match.1) ?? 0
    }
  } else {
    let regex = try? NSRegularExpression(pattern: "number = (\\d+),")
    let inputRange = NSRange(location: .zero, length: input.count)
    if let result = regex?.firstMatch(in: input, range: inputRange),
       let range = Range(result.range(at: 1), in: input) {
      id = Int32(input[range]) ?? 0
    }
  }
  return id
}

public enum Timber {
  public static func v(_ items: Any..., file: String = #file, line: Int = #line, separator: String = " ") {
    prepareLog(.VERBOSE, items, file, line, separator)
  }
  
  public static func d(_ items: Any..., file: String = #file, line: Int = #line, separator: String = " ") {
    prepareLog(.DEBUG, items, file, line, separator)
  }
  
  public static func i(_ items: Any..., file: String = #file, line: Int = #line, separator: String = " ", category: String = "") {
    prepareLog(.INFO, items, file, line, separator)
  }
  
  public static func w(_ items: Any..., file: String = #file, line: Int = #line, separator: String = " ") {
    prepareLog(.WARN, items, file, line, separator)
  }
  
  public static func e(_ items: Any..., file: String = #file, line: Int = #line, separator: String = " ") {
    prepareLog(.ERROR, items, file, line, separator)
  }
  
  private static func prepareLog(_ priority: Timber.Priority, _ items: [Any], _ file: String, _ line: Int, _ separator: String) {
    let message = items.map { String(describing: $0) }.joined(separator: separator)
    let wrapperMessage = String(format: "[%02d] %@[%d] %@", getThreadId(), getSimpleName(file), line, message)
    log(priority, wrapperMessage)
  }
  
  private static let lock = NSLock()
  private static func log(_ priority: Timber.Priority, _ message: String) {
    if Thread.current.isMainThread {
      os_log("%s", type: priority.type, message)
    } else {
      lock.lock()
      os_log("%s", type: priority.type, message)
      lock.unlock()
    }
  }
}

extension Timber {
  public enum Priority: String, CaseIterable {
    case VERBOSE = "V"
    case DEBUG = "D"
    case INFO = "I"
    case WARN = "W"
    case ERROR = "E"
    
    var type: OSLogType {
      switch self {
      case .VERBOSE: return  OSLogType.debug // 开发中信息
      case .DEBUG: return OSLogType.info // 故障排除的帮助信息
      case .INFO: return OSLogType.default // 故障级信息
      case .WARN: return OSLogType.error // 进程级错误
      case .ERROR: return OSLogType.fault // 系统级或多进程信息
      }
    }
  }
}
